Scite에서 루아 사용하는 법

전역 루아 함수는 무엇이든 SciTE 명령어로 사용할 수 있다. 이 함수들은 도구 메뉴에 나타나며 단축키와 연관되어 있다.

다음은 간단한 예이다; 다음을 특성 파일에 넣자 (local, user 또는 global):

command.name.1.*=Load Lua
command.1.*=dofile $(FilePath)
command.subsystem.1.*=3

이제 도구 메뉴에 'Load Lua'라고 부르는 메뉴 아이템이 있다. 기본값으로, 단축키는 Ctrl+1이다. command.subsystem은 반드시 3으로 설정하여야 하며, 이것이 루아 확장이다. 이 경우, 전역 루아 함수는 dofile이며 SciTE의 Lua 5에 있는 함수이다. 이 경우에 너무 유용하기 때문에 보관된다; dofile 다음에 인자 리스트가 없음에 유의하자. 기껏해야 인자 하나를 함수에 건넬 수 있을 뿐이다. 그러나 SciTE 특성 파일에서 그런 것처럼, 현재 보이는 파일의 완전한 경로를 가리키는 FilePath와 같이, 다른 SciTE 특성을 가리키는 참조점을 포함할 수 있다. (SciTE 매뉴얼의 '특성 파일' 부분에서 이런 동적 특성의 완전한 목록을 보자)

이제, 다음이 담긴 파일을 편집할 때:

  print ("Hello, World!")

Ctrl+1을 누르면, "Hello, World"가 SciTE 출력 창에 나타난다. 이 파일을 수정하면, SciTE가 먼저 저장하라고 재촉한다; 이것이 기본 행위이다. 이것은 루아 프로그래밍을 SciTE 환경에서 시작하는 강력한 방법이다.

이 정의에는 잠재적인 문제가 하나 있다; 다른 스크립트도 명령어 1에 정의될 가능성이 있다; 명령어를 이 메쏘드로 0에서 9까지 정의하여, Ctrl+0 .. Ctrl+9까지 묶을 수 있다. 그러나 이 정의에서 50보다 작은 숫자면 무엇이든 가능하다. 명시적으로 단축키를 제공하기만 하면 된다:

command.name.11.*=Load Lua
command.11.*=dofile $(FilePath)
command.subsystem.11.*=3
command.mode.11.*=savebefore:yes
command.shortcut.11.*=F9

SciTE나 Scintilla에 이미 정의된 키라도 다시 묶을 수 있다. 정의된 키가 많으므로, 문서를 참고하자.

다음은 문서를 디스크에 저장하도록 요구하지 않는 방법이다 - 현재 버퍼에 있는 모든 소스를 실행한다:

command.name.1.*=Run Document as Lua Extension
command.1.*=dostring dostring(editor:GetText())
command.subsystem.1.*=3
command.mode.1.*=savebefore:no

간단한 SciTE 매크로

다음 코드를 루아 파일로 (test.lua) 홈 디렉토리에 배치하자

function make_uppercase()
  local sel = editor:GetSelText()
  editor:ReplaceSel(string.upper(sel))
end

그리고 특성 파일에 다음 코드를 넣자

ext.lua.startup.script=$(SciteUserHome)/test.lua

command.name.12.*=Make Selection Uppercase
command.12.*=make_uppercase
command.subsystem.12.*=3
command.mode.12.*=savebefore:no
command.shortcut.12.*=Ctrl+M

이제, 텍스트를 선택하면, Ctrl+M을 눌러 대문자로 바꿀 수 있다. savebefore:no 때문에, 실행하기 전에 저장하라는 재촉을 하지 않을 것이다.

좋다. 이미 SciTE에 그런 연산이 있다. 그러나 무엇이든 SciTE에서 루아로 할 수 있다! 배우는 좋은 방법을 제시하자면 dofile 트릭을 사용하여 실험해 보는 것이다.

Scintilla 함수의 올바른 형태를 찾기

루아 신틸라 바인딩에 대한 최고의 참조서는 scintilla.iface이다. 이것은 Scintilla 디렉토리에 있다. GetLength를 찾아 보면:

 # 문서에서 문자의 개수를 돌려준다.
 get int GetLength=2006(,)

'get'의 의미는 Length라고 부르는 읽기-전용 특성이 있다는 뜻이다. 다음과 같이 호출한다: editor.Length.

반면에 GetText를 찾아 보면:

 # 문서의 모든 텍스트를 열람한다.
 # 열람한 문자의 개수를 돌려준다.
 fun int GetText=2182(int length, stringresult text)

그래서 GetText는 문자열을 건네는 평범한 함수이다. editor:GetText()이 될 것이다 - 쌍점에 주의하자!

루아 바인딩이 언제나 일관성이 있는 것은 아니다. 예를 들어 GetSelText는 함수이지 특성이 아니다.

루아 인터페이스를 위하여 주석을 붙인 Scintilla 문서는 다음에서 볼 수 있다: http://www.scintilla.org/ScintillaDoc.html

문서 텍스트를 얻고 수정하는 법

editor:GetText()는 현재 문서의 텍스트를 모두 돌려준다. 그리고 editor:SetText(s)는 현재 문서의 내용을 문자열 s로 교체한다.

editor:GetLine(n)n 번 줄의 텍스트를 줄끝문자까지 포함하여 모두 얻는다. 윈도우즈에서는 줄끝 문자가 두개임을 기억하자 ('\r\n'); 모든 줄 번호는 0-기반이다. 다음은 줄끝 문자를 제거하는 간단한 함수이다:

  -- 문자열에서 줄끝문자를 제거한다
  function Chomp(line)
    return string.gsub(line, "[\r\n]+$", "")
  end

editor:GetSelText()는 현재 선택된 텍스트를 열람한다.

문자 개수로 문서의 길이는 editor.Length이고 줄 개수로 하면 editor.LineCount이다; 여기에 사용된 구문에 주의하자. LengthLineCount는 특성(properties)이기 때문이다. 또다른 예는 editor.CharAt[p]로서 문자(character)를 p 위치에서 얻는다. 문자 코드가 반환되므로, string.char(ch)를 사용하여 문자열을 만들어야 한다:

  -- 주어진 위치의 문자를 문자열로 돌려준다
  function char_at(p)
     return string.char(editor.CharAt[p])
  end

editor:textrange(p1,p2)p1p2 사이의 텍스트를 얻는다; (this is a SciTE pane function). 그래서 p 위치에서 문자열로 문자를 얻는 또다른 방법은 editor:textrange(p,p+1)이다.

editor:ClearAll()는 문서를 없앤다.

editor:AppendText(s)s를 문서의 끝에 추가하고, editor:InsertText(p,s)sp 위치에 삽입한다; -1이 위치이면 현재 위치를 뜻한다. 즉 캐럿이 현재 화면에 보이는 곳이다; 모든 경우 InsertText가 텍스트를 스크롤하여 보이도록 해주지 않는다는 것을 주목하자. editor:ScrollCaret()가 그 일을 해준다.

editor:ReplaceSel(s)는 선택을 s로 교체한다. 다음은 선택된 텍스트를 볼드 태그로 둘러싸는 함수이다:

  function make_bold()
    local txt = editor:GetSelText();
    editor:ReplaceSel('<b>'..txt..'</b>')
  end

선택과 위치 정보

새로운 위치로 이동하려면, editor:GotoPos(p) 또는 editor:GotoLine(l)을 사용하자. 언제나 캐럿이 보이도록 만든다.

위치 p가 주어지면, editor:LineFromPosition(p)는 그 줄로 가고 editor:PositionFromLine(l)는 그 줄의 시작 위치로 간다. 줄끝의 위치가 필요하면, editor.LineEndPosition[l]을 사용하자 (특성은 마치 배열처럼 접근한다).

editor.CurrentPos는 현재의 캐럿 위치를 돌려준다; 이것은 쓰기가 가능한 특성이다. 그래서 editor.CurrentPos = p도 작동하지만, editor:GotoPos(p)와 의미가 같은 것은 아니다. Scintilla에서 선택은 앵커(anchor)와 위치(position) 사이이다. 그래서 기존에 선택이 있을 경우, 그 위치를 직접 설정하면 그 선택이 바뀌어 버린다. editor:SetSel(p1,p2)가 명시적으로 선택을 설정하는 가장 좋은 방법이다.

문서에서 현재 보이는 부분을 알아내려면, editor.FirstVisibleLine을 사용하여 시작 줄 번호를 알아내고 editor.LinesOnScreen를 사용하여 페이지에서 보이는 줄의 개수를 알아내면 된다.

center_pos()는 이 정보를 사용하여 일정 위치를 중심으로 화면을 중앙에 놓는 유용한 함수이다.

 -- 이 함수는 커서 위치를 가운데에 배치한다
 function center_pos(line)
  if not line then 
     -- 다음이 현재줄이다
     line = editor:LineFromPosition(editor.CurrentPos)
  end
  local top = editor.FirstVisibleLine
  local middle = top + editor.LinesOnScreen/2
  editor:LineScroll(0,line - middle)
 end

SciTE 특성

props라고 부르는 의사-배열이 있다. 이를 통하여 정의된 SciTE 특성에 얼마든지 접근할 수 있다. 예를 들어, props['FilePath']는 현재 편집중인 파일의 완전한 경로를 돌려준다. 다음은 C++ 파일을 그의 헤더와 바꾸는 아주 간단한 함수이다. 확장은 .cpp 그리고 .h라고 간주한다:

  function swap_header()
    local cpp_ext = 'cpp'
    local h_ext = 'h'
    local f = props['FileName']    -- e.g 'test'
    local ext = props['FileExt']   -- e.g 'cpp'
    local path = props['FileDir']  -- e.g. '/home/steve/progs'
    if ext == cpp_ext then
       ext = h_ext
    elseif ext == h_ext then
       ext = cpp_ext
    end
    scite.Open(path..'/'..f..'.'..ext)
  end

SciTE 문서의 '특성 파일' 부분에서 환경에서 설정되는 완전한 특성 목록을 살펴보자.

View|Parameters에 정의된 매개변수들은 prop[1],prop[2],prop[3] 그리고 prop[4]와 같이 접근할 수 있음에 유의하자.

물론 정의된 특성은 무엇이든 접근할 수 있다. 예를 들어 props['position.height']는 SciTE 창의 최초 높이를 돌려준다. 특수 특성들은 스크립트에서 오직 읽기 전용으로만 읽도록 정의할 수 있다. swop_header()를 좀 더 일반적으로 만들려면, 'cpp.swop.ext'라는 특성이 C++ 소스 확장이 되도록 정의하고 여기에cpp_ext를 설정하자.

  local cpp_ext = props['cpp.swop.ext']
  ...
다음 지역 특성 파일에 'cpp.swop.ext=cxx' (기타 등등)을 정의하자.

스크립트가 특성을 바꿀 수 있다. 물론 임시적이기는 하지만 말이다. 다음은 스크립트 개발자의 삶을 더 편안하게 해 준다; 보통, 호출될 루아 함수는 특성 파일에 지정할 필요가 있지만, 자동으로 생성되지 말란 법은 없다. 다음은 SciteExtManscite_Command의 주요 부분이다.

     -- we are fed something like 'Process File|ProcessFile|Ctrl+M'
     local name,cmd,shortcut = split3(v,'|')
     local which = '.'..idx..'.*'
     props['command.name'..which] = name
     props['command'..which] = cmd     
     props['command.subsystem'..which] = '3'
     props['command.mode'..which] = 'savebefore:no'
     props['command.shortcut'..which] = shortcut

찾기와 바꾸기

현재 문서에서 텍스트를 찾으려면, editor:findtext()을 사용하자. 반환된 범위를 나타내는 I두 개의 위치를 돌려준다. 아무 일치도 발견되지 않으면, nil이다. 다음 함수는 주어진 텍스트가 있는 줄들을 모두 인쇄한다:

  function all_lines_with_text(txt,flags)
    if not flags then flags = 0 end
    local s,e = editor:findtext(txt,flags,0)
    while s do 
      local l = editor:LineFromPosition(s)
      trace(l..' '..editor:GetLine(l))
      s,e = editor:findtext(txt,flags,e+1)
    end    
  end

(여기에서 print() 대신에 trace()를 사용하고 있는 이유는 그 줄에 이미 줄넘김문자가 있기 때문이다)

search flags는 SCFIND_MATCHCASE, SCFIND_WHOLEWORD, SCFIND_WORDSTART, 그리고 SCFIND_REGEXP를 조합한 것이다. 기본으로 검색은 평범한 대소문자 구분 검색이다. all_lines_with_text('for',SCFIND_WHOLEWORD)는 C 파일에서 모든 for-서술문들을 보여주고, all_lines_with_text('^#',SCFIND_REGEXP)는 모든 전처리 서술문들을 보여준다 (즉, '#'가 줄의 처음에 나타나면). SciTE 정규 표현식은 루아와 다르다는 사실을 주의하자 - 자세한 것은 http://scintilla.sourceforge.net/ScintillaDoc.html 문서의 '검색' 부분을 찾아보자.

검색과 치환을 가장 쉽게 하는 방법은 editor:match()을 사용하는 것이다. 그러면 반복자를 돌려준다:

  function replace_all(target,repl)
    editor:BeginUndoAction()
    for m in editor:match(target) do
      m:replace(repl)
    end
    editor:EndUndoAction()
  end

BeginUndoAction()를 사용하는 것이 많은 변화를 단번에 원래대로 돌려놓는 일반적인 방법이다.

표식(Markers)

SciTE는 표식을 사용하여 줄에 에러 표식을 붙이고 책갈피 같은 것들을 구현한다. 32가지 표식이 있다. Scintilla는 0부터 24까지 표식을 일반적인 목적으로 사용한다; SciTE는 0을 에러 있는 줄에 사용하고 1을 책갈피에 사용한다. 예를 들어, editor:MarkerAdd(line,1)은 책갈피를 line에 끼우고, SciTE는 그것을 다른 책갈피와 똑같이 취급한다. 내부의 신틸라 리스트를 사용하여 책갈피를 찾기 때문이다. 언제나와 같이 신틸라는 줄을 0부터 센다는 것을 기억하자.

다음은 맞춤 표식을 정의하는 유용한 함수이다:

  local colours = {red = "#FF0000", blue = '#0000FF', green = '#00FF00',pink ="#FFAAAA" ,
					black = '#000000', lightblue = '#AAAAFF',lightgreen = '#AAFFAA'}

  function colour_parse(str)
    if sub(str,1,1) ~= '#' then
      str = colours[str]
    end
    return tonumber(sub(str,6,7)..sub(str,4,5)..sub(str,2,4),16)
  end

  function marker_define(idx,typ,fore,back)
    editor:MarkerDefine(idx,typ)
    if fore then editor:MarkerSetFore(idx,colour_parse(fore)) end
    if back then editor:MarkerSetBack(idx,colour_parse(back)) end
  end

사용자 리스트

다음은 사용자가 항목 중에서 하나를 고를 수 있는 드롭-다운 리스트이다. 이 리스트를 SciTE는 'Complete Symbol', 등등에 사용한다. 사용하기에 어렵지 않다; 지정된 가름 문자로 문자열을 공급한다. 사용자가 항목을 선택하면 OnUserListSelection 이벤트가 촉발된다.

 function UserListShow(list)
   local s = ''
   local sep = ';'
   local n = table.getn(list)
   for i = 1,n-1 do
      s = s..list[i]..sep
   end
   s = s..list[n]
   editor.AutoCSeparator = string.byte(sep)
   editor:UserListShow(12,s)
   editor.AutoCSeparator = string.byte(' ')
 end

여기에서 좀 어려운 것은 AutoCSeparator 특성이 문자열이 아니라 문자 코드에 건네진다는 것이다. '12'는 그냥 숫자이다. SciTE가 내부적으로 사용하지 않는다.

다음은 문자열이 어떤 디렉토리에 존재하는 루아 스크립트를 가리킨다고 가정하는 이벤트 처리자이다. 여기에서 아이디어는 사용자에게 "한번 쓰고 버릴" 스크립트들을 담은 리스트를 보여주는 것이다. 그렇지 않으면 아마도 도구 메뉴에 들어 갔을 것이다.

 function OnUserListSelection(tp,script)
   if tp == 12 then 
      dofile(path..'/'..script..'.lua')
   end
 end

파일 리스트를 구축하려면 좀 수고가 필요하다. 다음은 이 문제를 창-없이 해결한다:

 function GetFiles(mask)
   local files = {}
   local tmpfile = '/tmp/stmp.txt'
   os.execute('ls -1 '..mask..' > '..tmpfile)
   local f = io.open(tmpfile)
   if not f then return files end  
   local k = 1
   for line in f:lines() do
      files[k] = line
      k = k + 1
   end
   f:close()
   return files
 end

코드가 유닉스와 윈도우즈에서 모두 작동하려면 약간 꼼수가 필요하다. 완전한 해결책은 SciteExtMan에서 scite_Files()를 보자.

지시자(Indicators)

지시자는 현재 SciTE에서 사용되지 않는다. 그러나 스크립트는 쉽게 추가할 수 있다. 철자 검사 유틸에서 잘못된 단어에 빨간줄을 그을 때 사용하거나, 엉터리 구문에는 구불구불한 초록색 줄을 긋는데 사용한다. SciTE 설정에서 세 가지 지시자를 사용할 수 있다. 다음은 주어진 지시자 (0,1 또는 2)를 사용하여 pos 위치에서 시작하여 len 개수의 문자만큼 빨간줄을 치는 예제이다.

 function underline_text(pos,len,ind)
   local es = editor.EndStyled
   editor:StartStyling(pos,INDICS_MASK)
   editor:SetStyling(len,INDIC0_MASK + ind)
   editor:SetStyling(2,31)
 end

밑줄을 제거하려면 underline_text(pos,len,-1)을 사용하자. 구문분석기의 상태를 복구하려면 마지막 SetStyling() 호출이 필요하다; 31은 하위 5 비트에 대한 마스크로서, 멋내기에 사용된다. 기본 값은 필요하면 바꿀 수 있다.

기본 지시자는 다음과 같다.

   0 구불구불한 초록색 줄.
   1 작은 T 모양으로 구성된 밝은 파랑 줄.
   2 밝은 빨강 줄.

사용가능한 지시자 스타일은 다음과 같다.

  INDIC_PLAIN       한 줄에 밑줄을 친다.
  INDIC_SQUIGGLE    구불구불한 밑줄.
  INDIC_TT          작은 T 모양으로 구성된 줄.
  INDIC_DIAGONAL    대각선 빗금.
  INDIC_STRIKE      취소선.
  INDIC_HIDDEN      시각적 효과를 감추는 지시자.
  INDIC_BOX         텍스트를 사각형으로 두른다.

1.70 이전 버전의 지시자

다음 플래그가 있다 :
   0 스타일 재설정
   INDIC0_MASK 초록색 단어 처리-류 줄
   INDIC1_MASK 기묘한 파랑색 줄
   INDIC2_MASK 파랑색 배경의 둥근 상자
다음과 같이 사용한다 :
editor:StartStyling(editor.SelectionStart,INDICS_MASK)
editor:SetStyling(string.len(editor:GetSelText()),flag)

FindPage · RecentChanges · preferences
edit · history
Last edited April 10, 2008 7:49 am GMT (diff)